#include "skitter.h"

using namespace std;

extern fstream& fileout;

namespace Cxuh{

	skitter::skitter(Btree3D* tree1) : tree(tree1)
	{
		model();
	}


	skitter::~skitter(void)
	{
		// free the maps containing pointers
		for(int i=0;i<=1;i++){
			empty_var_set(dvar_buf_set[i]);
			empty_var_set(dvar_wire_set[i]);
			empty_var_set(tvar_buf_set[i]);
			empty_var_set(tvar_wire_set[i]);
		}
	}

	void skitter::empty_var_set(map<string, Variation*>& var_set){
		// empty the variation sets
		map<string, Variation*>::iterator it;
		for(it = var_set.begin();it!=var_set.end();it++){
			delete_var_list((*it).second);
		}
	}

	void skitter::delete_var_list(Variation* variation){
		// delete a variable list
		if(variation){
			delete_var_list(variation->getNext());
			delete variation;
		}
	}

	void skitter::gen_variation(const BtreeNode* rt, const int clk_edge){
		// generate variation list for each node
		if(rt){
			string rt_name = rt->getName();
			char rt_type = rt->getType();
			Variation *new_dvar = NULL;
			Variation *new_tvar = NULL;
			string var_name = "";
			double dvar_cof = 0;
			double tvar_cof = 0;
			int var_edge = clk_edge-1;
			unsigned int n=0;

			// generate node variations
			switch(rt_type){
			case 'b':
				n = this->buf_var_types.size();
				for(unsigned int i = 0;i< n;i++){
					var_name = rt_name + "_"+ buf_var_types.at(i);
					// add a delay variation
					new_dvar = new Variation(var_name, dvar_cof);
					dvar_buf_set[var_edge][var_name] = new_dvar;

					// add a transition variation
					new_tvar = new Variation(var_name, tvar_cof);
					tvar_buf_set[var_edge][var_name] = new_tvar;
				}
				break;
			case 't':
				// tsv variation is also included in var_wire_set
				n = this->tsv_var_types.size();
				for(unsigned int i = 0;i < n;i++){
					var_name = rt_name + "_"+ tsv_var_types.at(i);
					// add a delay variation
					new_dvar = new Variation(var_name, dvar_cof);
					dvar_wire_set[var_edge][var_name] = new_dvar;

					// add a transition variation
					new_tvar = new Variation(var_name, tvar_cof);
					tvar_wire_set[var_edge][var_name] = new_tvar;
				}
				break;
			}

			// add the previous wire variations
			if(rt->getParent()){
				if(!rt->get_pre_wire()){
					string errstr = " Error: " + rt_name + " has a parent but no pre wire!";
					throw(errstr.c_str());
				}else{
					var_name = rt->get_pre_wire()->getName();
					n = wire_var_types.size();
					for(unsigned int i = 0;i< n;i++){
						var_name = var_name + "_"+ wire_var_types.at(i);
						// add a delay variation
						new_dvar = new Variation(var_name, dvar_cof);
						dvar_wire_set[var_edge][var_name] = new_dvar;

						// add a transition variation
						new_tvar = new Variation(var_name, tvar_cof);
						tvar_wire_set[var_edge][var_name] = new_tvar;
					}
				}
			}



			// recursively generate variation for children
			gen_variation(rt->getLchild(), clk_edge);
			gen_variation(rt->getRchild(), clk_edge);
		}
	}

	void skitter::model(){
		// model the skitter

		// generate variations for all nodes for 1st and 2nd clock edges
		gen_variation(tree->getRoot(), 1); // 1st clock edge
		gen_variation(tree->getRoot(), 2); // 2nd clock edge


	}

}
